package algorithm;

import util.NumberUtil;

import java.lang.annotation.Native;
import static constant.NumberConstant.*;

/**
 * 其他算法整理，包括：
 * 字符串压缩
 * 字符串解压缩
 * 指定str 和radix 转为Long型数字
 *
 * 其中核心思想 char 和 int 互转。使用char型加减
 *
 * @Author Antony
 * @Since 2018/5/9 12:34
 */
public class OtherAlgorithm {


    // 字符串压缩
    // 如果压缩后的结果没有变短，则返回原字符串
    public void testStringCompress(){
        String str = "aaabbbbcddddaaccc";
        System.out.println(stringCompress(str));
    }

    /**
     * for循环遍历字符数组，循环外用Stringbuilder接收
     * 循环中不相同时候向bu里添加，循环结束再加一次
     */
    private String stringCompress(String str){
        if(str.length() == 1){
            return str;
        }

        char[] arr = str.toCharArray();
        char temp = arr[0];
        int index = 1;
        int count = 1;
        StringBuilder bu = new StringBuilder();

        //******核心代码******
        while(index < arr.length){
            if(arr[index] == temp){
                count++;
            }else {
                bu.append(temp);
                if(count > 1){
                    bu.append(count);
                }
                temp = arr[index];
                count = 1;
            }
            index++;
        }
        bu.append(temp);
        if(count > 1){
            bu.append(count);
        }
        return bu.toString().length() < str.length() ? bu.toString() : str;
    }


    //字符串解压缩
    public void testStringUncompress(){
        String str = "a2b2cj7";
        System.out.println(stringUncompress(str));
    }

    /**
     * 思路：判断每个字符是不是数字。如果是数字则表示前一个字符的数量，并相应index向后移一位
     */
    private String stringUncompress(String str){
        if(str == null || str.length() <= 1){
            return str;
        }

        char[] arr = str.toCharArray();
        char temp = arr[0];
        int next;
        StringBuilder bu = new StringBuilder();
        for(int i=1; i<arr.length; i++){
            next = arr[i] - '0';   //尝试转成数字
            if(next > 0 && next < 10){  //如果是数字就循环加数字
                while (next > 0){
                    bu.append(temp);
                    next--;
                }
            }else{
                temp = arr[i];
                bu.append(temp);
            }
        }

        return bu.toString();
    }



    //给定字符串和进制，转换为十进制的Long型数
    public void parseRadix(){
        String str = "Antony";
        int radix = 36;

        System.out.println(Long.parseLong(str,radix));
        System.out.println(myParseLong(str,radix));

        char[] charArray = {'+','0','A','F','Z','~'};
        for(char c : charArray){
            System.out.println(NumberUtil.digit(c,16));
        }

    }


    @Native private static long MIN_VALUE = 0x8000000000000000L;    //长整型最小值 -2的63次方。长整型占四个字节
    @Native private static long MAX_VALUE = 0x7fffffffffffffffL;    //长整型最大值  2的63次方减1

    /**
     * 思路: abc=((a*r)+b)*r + c。
     * 高位*radix + 低位。还有低位时，前面整个结果*radix再加低位。
     *
     * 难点:char转指定类型的int值
     * 注意点:
     * 1，校验，字符是否未null，是否为空。radix在2~36之间。也就是10数字+26字母
     * 2，注意首位是否有符号。
     * 3，每次循环的计算结果都要判断是否超过界
     * 4，
     */
    private Long myParseLong(String str, int radix) throws NumberFormatException{

        //判断str是否合法
        if(str == null){
            throw new NumberFormatException("null");
        }
        if(str.length() < 1){
            throw new NumberFormatException("for Input string :" + str);
        }

        //判断radix是否合法
        if(radix<MIN_RADIX || radix>MAX_RADIX){
            throw new IllegalArgumentException("radix is illegal");
        }


        boolean nagetive = false;
        int index = 0, len = str.length();
        long bottomLimit = -MAX_VALUE;

        //判断首字符是否有正负号
        // ASCII码下，"+" "-" 号ASCII码在0之前 之后是大写英文字母和小写英文字母
        if(str.charAt(0) < '0'){
            char first = str.charAt(index);
            if(first == '-'){
                nagetive = true;
                bottomLimit = MIN_VALUE;
            }else if(first != '+'){
                throw new NumberFormatException("for Input string :" + str);
            }

            //如果只有正负号，同样不能转，抛异常
            if(len == 1){
                throw new NumberFormatException("for Input string :" + str);
            }

            //index从1开始
            index = 1;
        }

        long result = 0;
        int dight;

        //******核心代码******
        while(index < len){
            //算出该字符的十进制表示
            dight = NumberUtil.digit(str.charAt(index++), radix);
            if(result < 0){
                throw new NumberFormatException("for Input string : " +str);
            }
            result += dight;
        }


        return nagetive ? -result : result;
    }



}
